/****************************************************************************/
/*                                                                          */
/*   FILE:    linkstat.c	                                                */
/*   DATE:    26/06/97                                                      */
/*   PURPOSE: DVB-CI Link layer - state diagram for LINK task				*/  
/*   TAB STOPS : 4															*/
/*   HISTORY:				                                 			    */
/*   Version    Date  		    Written by	     Notes	    	    		*/
/*	 1.0	    26/06/1997      SCM              Initial implementation 	*/
/*                                                                    	    */
/*--------------------------------------------------------------------------*/
/*   GENERAL COMMENTS                                                 	    */
/*																		    */
/****************************************************************************/
#include <stdio.h>
#include <memory.h>
#include "sm_trace.h"
#include "itc.h"				/* Inter-Task Communication	*/
#include "link.h"               /* Main Module			  	*/


/*--------------------------------------------------------------------------*/
/* External Variables		                                            	*/
/*--------------------------------------------------------------------------*/
extern lslot_t g_lnk_tab_slot[]; /* slot table   								*/
extern ltcid_t g_lnk_tab_tcid[]; /* tcid table   								*/


/* ======================================================================== */
/* NAME : LINK_Action					 									*/
/* 									    									*/
/* DESCRIPTION : Activate the action associated to the current state 		*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		lnkSlotIndex :		instance of the current state diagram					*/
/*		evt :		current event (transition)								*/
/*		nExtraInfo :		conditionnal information according to the event			*/
/*									 										*/
/* RETURN CODE								    							*/
/*		1 : Success															*/
/*		0 : Error															*/
/*									  										*/
/* ======================================================================== */
int LINK_Action(int lnkSlotIndex, unsigned char evt, int nExtraInfo, xmsg_t* pXmsg)			    
{
	int iRet;			/* return code 				*/

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Action() - entry,lnkSlotIndex=%d,evt=%s(0x%02X),nExtraInfo=%d\r\n",
					lnkSlotIndex, XMSG_NAME(evt), evt, nExtraInfo);

	SM_TRACE_INFO(TRMOD_LINK,"LINK_Action() - after entry, lnkSlotIndex=%d curstate=%s(%d) "
					"evt=%s(0x%02X)\r\n", 
					lnkSlotIndex, 
					GETLINKSTATNAME(g_lnk_tab_slot[lnkSlotIndex].m_state), 
					g_lnk_tab_slot[lnkSlotIndex].m_state, 
					XMSG_NAME(evt),
					evt);

	switch(g_lnk_tab_slot[lnkSlotIndex].m_state) 
	{
	case LN_STAT_IDLE : 
		iRet = LINK_Idle(lnkSlotIndex, evt);
		break;

	case LN_STAT_CONNECTED : 
		iRet = LINK_Connected(lnkSlotIndex, evt, nExtraInfo, pXmsg);
		break;
			
	case LN_STAT_SEND : 
		iRet = LINK_Send(lnkSlotIndex, evt, nExtraInfo, pXmsg);
		break;
		

	default : 
		SM_TRACE_ERROR(TRMOD_LINK,"LINK_Action() - Unknown state %d\r\n", g_lnk_tab_slot[lnkSlotIndex].m_state);
		iRet = 0;	/* Error */
		break;
	}//end switch

	SM_TRACE_INFO(TRMOD_LINK,"LINK_Action() - before return, lnkSlotIndex=%d curstate=%s(%d) "
					"evt=%s(0x%02X)\r\n", 
					lnkSlotIndex, 
					GETLINKSTATNAME(g_lnk_tab_slot[lnkSlotIndex].m_state), 
					g_lnk_tab_slot[lnkSlotIndex].m_state, 
					XMSG_NAME(evt),
					evt);

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Action() - return,iRet=%d\r\n", iRet);
	return iRet;	
}

                                                                          
/* ======================================================================== */
/* NAME : LINK_Idle						 									*/
/* 									    									*/
/* DESCRIPTION : Execute the action of the LN_STAT_IDLE state						*/
/*		There is a new DVB module inserted . The Link layer sends the		*/
/*		connection indication to the TRANS layer							*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		lnkSlotIndex :		instance of the current state diagram					*/
/*		evt :		current event (transition)								*/
/*									 										*/
/* RETURN CODE								    							*/
/*		1 : Success															*/
/*		0 : Error															*/
/*									  										*/
/* ======================================================================== */
int LINK_Idle(int lnkSlotIndex, unsigned char evt)
{                                                                          
	int			iRet;
	xmsg_t		xmsg;

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Idle() - entry,lnkSlotIndex=%d,evt=%s(0x%02X)\r\n",
					lnkSlotIndex, XMSG_NAME(evt), evt);

	SM_TRACE_INFO(TRMOD_LINK,"LINK_Idle() - after entry, lnkSlotIndex=%d curstate=%s(%d) "
					"evt=%s(0x%02X)\r\n", 
					lnkSlotIndex, 
					GETLINKSTATNAME(g_lnk_tab_slot[lnkSlotIndex].m_state), 
					g_lnk_tab_slot[lnkSlotIndex].m_state, 
					XMSG_NAME(evt),
					evt);

	switch(evt) 
	{
	case LN_CONNECT :						
	
		/* send TP_CONNECT to the Transport Task */
		/* =============== */
		memset(&xmsg, 0x00, sizeof(xmsg));
		xmsg.m_sndrcver	= (LINK << 4) | TRANS;
		xmsg.m_type     	= TP_CONNECT;
		xmsg.m_bd.m_tran_conn.m_slotId  = g_lnk_tab_slot[lnkSlotIndex].m_slotId;
    
	    /* Send the message */
    	if (!ITC_SendXmsg(&xmsg))
    	{
			SM_TRACE_ERROR(TRMOD_LINK, "LINK_Idle() - Can't send the TP_CONNECT for %d slot to TRANS Task\r\n", g_lnk_tab_slot[lnkSlotIndex].m_slotId);
			return 0;		/* Error */
		}
		else
		{
	    	/* Set the new state */
			g_lnk_tab_slot[lnkSlotIndex].m_state = LN_STAT_CONNECTED;
			iRet = 1;		/* Success */
		}
		break;	/* end of LN_CONNECT processing */

	default :	/* protocol error, ignore the event */
		SM_TRACE_ERROR(TRMOD_LINK, "LINK_Idle() - protocol error .event %d received in %d state\r\n", evt, g_lnk_tab_slot[lnkSlotIndex].m_state);
		iRet = 0;
		break;			
	}

	SM_TRACE_INFO(TRMOD_LINK,"LINK_Idle() - before return, lnkSlotIndex=%d curstate=%s(%d) "
					"evt=%s(0x%02X)\r\n", 
					lnkSlotIndex, 
					GETLINKSTATNAME(g_lnk_tab_slot[lnkSlotIndex].m_state), 
					g_lnk_tab_slot[lnkSlotIndex].m_state, 
					XMSG_NAME(evt),
					evt);

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Idle() - return,iRet=%d\r\n", iRet);
	return iRet;
}	/* end of LN_STAT_IDLE state */
	

/* ======================================================================== */
/* NAME : LINK_Connected						 							*/
/* 									    									*/
/* DESCRIPTION : Execute the action of the LN_STAT_CONNECTED state					*/
/*		- Send TPDU to PHYSICAL task into LPDU if no LPDU are waiting for	*/
/*		acknowlegde															*/
/*		- Receive LPDU from PHYSICAL task, assemble LPDU into complete		*/
/*		TPDU and send them to TRANS Task									*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		lnkSlotIndex :		instance of the current state diagram					*/
/*		evt :		current event (transition)								*/
/*		nExtraInfo :		conditionnal information according to the event			*/
/*			evt = TPDU /LPDU :  nExtraInfo = lnkSlotIndex of g_lnk_tab_tcid					*/
/*			evt = LN_ERROR : 	nExtraInfo = status of error						*/
/*									 										*/
/* RETURN CODE								    							*/
/*		1 : Success															*/
/*		0 : Error															*/
/*									  										*/
/* ======================================================================== */
int LINK_Connected(int lnkSlotIndex, unsigned char evt, int nExtraInfo, xmsg_t* pXmsg)
{                                                                          
	int iRet = 0;		/* return code  								*/
	int tcidIndex;	/* index of g_lnk_tab_tcid							*/                      
	unsigned short len;		/* length of received LPDU		 		*/
	unsigned char *plpdu;	/* pointer to the received LPDU			*/
	unsigned char *ptr;		/* pointer to reallocated memory		*/
	unsigned char flag;		/* flag More/Last of the received LPDU 	*/
	xmsg_t		xmsg;

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Connected() - entry,lnkSlotIndex=%d,evt=%s(0x%02X),nExtraInfo=%d\r\n",
					lnkSlotIndex, XMSG_NAME(evt), evt, nExtraInfo);

	SM_TRACE_INFO(TRMOD_LINK,"LINK_Connected() - after entry, lnkSlotIndex=%d curstate=%s(%d) "
					"evt=%s(0x%02X)\r\n", 
					lnkSlotIndex, 
					GETLINKSTATNAME(g_lnk_tab_slot[lnkSlotIndex].m_state), 
					g_lnk_tab_slot[lnkSlotIndex].m_state, 
					XMSG_NAME(evt),
					evt);

	switch(evt)
	{
	case LPDU :						
		tcidIndex = nExtraInfo;			     
		SM_TRACE_INFO(TRMOD_LINK,"LINK_Connected() - is LPDU, tcidIndex=%d\r\n", tcidIndex);

		SM_TRACE_BYTES(TRMOD_LINK, TRLEV_NOTIFY, 
					pXmsg->m_bd.m_lpdu.m_pbLpdu, pXmsg->m_bd.m_lpdu.m_len,
					"LINK_Connected() - recv data[slotId=%d]:", 
					pXmsg->m_bd.m_lpdu.m_slotId);

		flag  = pXmsg->m_bd.m_lpdu.m_pbLpdu[1] & LN_MORE; 
		len   = pXmsg->m_bd.m_lpdu.m_len - 2;                      
		plpdu = pXmsg->m_bd.m_lpdu.m_pbLpdu + 2;

		if (flag ==	LN_MORE)
		{
			/* size control . the size must be equal to the negociated size since flag = MORE */
			if (g_lnk_tab_slot[lnkSlotIndex].m_negoSize != pXmsg->m_bd.m_lpdu.m_len)
			{
				SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - bad lpdu size (%d) for intermediate received LPDU on slotId %d . The negociated size is %d\r\n", 
						pXmsg->m_bd.m_lpdu.m_len, g_lnk_tab_slot[lnkSlotIndex].m_slotId, g_lnk_tab_slot[lnkSlotIndex].m_negoSize);
				return 0;	/* Error */
			}                               

			/* begin or concatenate a TPDU */
			if (g_lnk_tab_tcid[tcidIndex].m_recvSize == 0)
			{
				/* new TPDU to begin */
				/* ================= */
				g_lnk_tab_tcid[tcidIndex].m_pbRecv = ITC_DynAlloc(len);
				if (g_lnk_tab_tcid[tcidIndex].m_pbRecv == NULL)
				{
					SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - can't allocate buffer for coding TPDU\r\n");
					return 0;	/* Error */
				}                               
				g_lnk_tab_tcid[tcidIndex].m_recvSize = len; 										
				memcpy(g_lnk_tab_tcid[tcidIndex].m_pbRecv, plpdu, len);
			}	
			else
			{   
				/* Add the LPDU to the already received LPDU : reallocate the memory */
				/* =========================================						 */
				ptr = ITC_DynReAlloc(g_lnk_tab_tcid[tcidIndex].m_pbRecv, 
							(unsigned short)(g_lnk_tab_tcid[tcidIndex].m_recvSize + len));
				if (ptr == NULL)
				{
					SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - can't reallocate buffer for coding TPDU\r\n");
					return 0;	/* Error */
				}                               
				g_lnk_tab_tcid[tcidIndex].m_pbRecv = ptr;
				memcpy(g_lnk_tab_tcid[tcidIndex].m_pbRecv + g_lnk_tab_tcid[tcidIndex].m_recvSize, plpdu, len);
				g_lnk_tab_tcid[tcidIndex].m_recvSize += len;
			}							
		}   
		else
		{	/* end of LPDU  : send the complete TPDU */
			memset(&xmsg, 0x00, sizeof(xmsg));
			if (g_lnk_tab_tcid[tcidIndex].m_recvSize == 0)
			{	/* one LPDU to code in TPDU and to send to the TRANS Task			*/
				/* ======================================================			*/
				/* Get xmsg.m_msg.m_body free buffer for TPDU message since pXmsg->m_msg.m_body / pXmsg->m_msg.m_body is for the LPDU */
			    /* Optimization : Fast small allocation since an only LPDU is more little than the fixed size of a memory segment */
			    /* ============	 (The fixed size of a memory segment is equal to the maximum negociated physical buffer size) added with a header message */
				xmsg.m_bd.m_tpdu.m_pbTpdu = ITC_DynAlloc(len);	/* length = len */
				if (xmsg.m_bd.m_tpdu.m_pbTpdu == NULL)
				{
					SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - can't allocate buffer for coding TPDU\r\n");
					return 0;	/* Error */
				}

				xmsg.m_sndrcver	 = (LINK << 4) | TRANS;
				xmsg.m_type      = TPDU;
				xmsg.m_bd.m_tpdu.m_slotId = g_lnk_tab_slot[lnkSlotIndex].m_slotId;
				xmsg.m_bd.m_tpdu.m_tcid    = g_lnk_tab_tcid[tcidIndex].m_tcid;
				xmsg.m_bd.m_tpdu.m_len	 = len;
				memcpy(xmsg.m_bd.m_tpdu.m_pbTpdu, plpdu, len);							
			}
			else
			{	
				/* Add the LPDU to the already received LPDU : reallocate the memory */
				/* =========================================						 */
				ptr = ITC_DynReAlloc(g_lnk_tab_tcid[tcidIndex].m_pbRecv, (unsigned short)(g_lnk_tab_tcid[tcidIndex].m_recvSize + len));
				if (ptr == NULL)
				{
					SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - can't reallocate buffer for coding TPDU\r\n");
					return 0;	/* Error */
				}                               
				g_lnk_tab_tcid[tcidIndex].m_pbRecv = ptr;
				memcpy(g_lnk_tab_tcid[tcidIndex].m_pbRecv + g_lnk_tab_tcid[tcidIndex].m_recvSize, plpdu, len);
				g_lnk_tab_tcid[tcidIndex].m_recvSize += len;
				
				/* Send concatenated TPDU to TRANS Task */
				/* ==================================== */
				xmsg.m_sndrcver	 = (LINK << 4) | TRANS;
				xmsg.m_type      = TPDU;			/* TPDU with dynamically allocated memory */
				xmsg.m_bd.m_tpdu.m_slotId = g_lnk_tab_slot[lnkSlotIndex].m_slotId;
				xmsg.m_bd.m_tpdu.m_tcid    = g_lnk_tab_tcid[tcidIndex].m_tcid;
				xmsg.m_bd.m_tpdu.m_len	 = g_lnk_tab_tcid[tcidIndex].m_recvSize;
				xmsg.m_bd.m_tpdu.m_pbTpdu   = g_lnk_tab_tcid[tcidIndex].m_pbRecv;
			}
			/* Send the complete TPDU to TRANS Task */
			/* ==================================== */
   			if (!ITC_SendXmsg(&xmsg))
   			{
				SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - Can't send the TPDU for %d slot to TRANS Task\r\n", g_lnk_tab_slot[lnkSlotIndex].m_slotId);
				FreeXmsg(&xmsg);
				iRet = 0;		/* Error   */
			}
			else
			{
				/* Reinitialize the precv since the TPDU is complete and sent to the TRANSPORT task */
				g_lnk_tab_tcid[tcidIndex].m_recvSize = 0;
				g_lnk_tab_tcid[tcidIndex].m_pbRecv = NULL;

				/* Don't change the state  */
				iRet = 1;		/* Success */
			}
		}                                                                           
		break;	/* end of LPDU processing */

	case TPDU :			
		tcidIndex = nExtraInfo;		
		SM_TRACE_INFO(TRMOD_LINK,"LINK_Connected() - is TPDU, tcidIndex=%d\r\n", tcidIndex);

		/* Send LPDU to PHYSICAL Task */
		/* ========================== */
		iRet = LINK_SendLPDU(lnkSlotIndex, tcidIndex, g_lnk_tab_tcid[tcidIndex].m_tcid,
						pXmsg->m_bd.m_tpdu.m_pbTpdu, pXmsg->m_bd.m_tpdu.m_len);
		if (iRet)	
		{
			pXmsg->m_bd.m_tpdu.m_pbTpdu = NULL; //pmy
	    	/* Set the new state */
			g_lnk_tab_slot[lnkSlotIndex].m_state = LN_STAT_SEND;	/* wait for the LN_ACK from PHYSICAL Task	*/
		}
		break;	/* end of TPDU processing */

	case LN_ERROR :						
		/* Send IHM_WARNING to IHM Task */
		if ((unsigned char)nExtraInfo == LN_PHYSICAL)
		{
			/* send TP_DISCONNECT to the Transport Task */
			/* ================== */
			memset(&xmsg, 0x00, sizeof(xmsg));
			xmsg.m_sndrcver		= (LINK << 4) | TRANS;
			xmsg.m_type     	= TP_DISCONNECT;
			xmsg.m_bd.m_tran_conn.m_slotId = g_lnk_tab_slot[lnkSlotIndex].m_slotId;
    
		    /* Send the message */
   			if (!ITC_SendXmsg(&xmsg))
   			{
				SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - Can't send the TP_DISCONNECT for %d slot to TRANS Task\r\n", g_lnk_tab_slot[lnkSlotIndex].m_slotId);
				return 0;		/* Error */
			}
			else
			{
		    	/* Set the new state */
				g_lnk_tab_slot[lnkSlotIndex].m_state = LN_STAT_IDLE;
				iRet = 1;		/* Success : LN_PHYSICAL */
			}
		}   
		else
			iRet = 0;		/* Success : LN_I2C */
		break;	/* end of LN_ERROR processing   */

	case LN_DISCONNECT :						
		/* send TP_DISCONNECT to the Transport Task */
		/* ================== */
		memset(&xmsg, 0x00, sizeof(xmsg));
		xmsg.m_sndrcver		= (LINK << 4) | TRANS;
		xmsg.m_type     	= TP_DISCONNECT;
		xmsg.m_bd.m_ln_disconn.m_slotId = g_lnk_tab_slot[lnkSlotIndex].m_slotId;
    
   		if (!ITC_SendXmsg(&xmsg))
   		{
			SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - Can't send the TP_DISCONNECT for %d slot to TRANS Task\r\n", g_lnk_tab_slot[lnkSlotIndex].m_slotId);
			return 0;		/* Error */
		}
		else
	    	/* Set the new state */
			g_lnk_tab_slot[lnkSlotIndex].m_state = LN_STAT_IDLE;

		iRet = 1;		/* Success */
		break;	/* end of LN_DISCONNECT processing */

	default :	/* protocol error, ignore the event */
		SM_TRACE_ERROR(TRMOD_LINK, "LINK_Connected() - protocol error . event %d received in %d state\r\n", evt, g_lnk_tab_slot[lnkSlotIndex].m_state);
		iRet = 0;
		break;			
	}

	SM_TRACE_INFO(TRMOD_LINK,"LINK_Connected() - refore return, lnkSlotIndex=%d curstate=%s(%d) "
					"evt=%s(0x%02X)\r\n", 
					lnkSlotIndex, 
					GETLINKSTATNAME(g_lnk_tab_slot[lnkSlotIndex].m_state), 
					g_lnk_tab_slot[lnkSlotIndex].m_state, 
					XMSG_NAME(evt),
					evt);

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Connected() - return,iRet=%d\r\n", iRet);
	return iRet;
}	/* end of LN_STAT_CONNECTED state */
	

/* ======================================================================== */
/* NAME : LINK_Send								 							*/
/* 									    									*/
/* DESCRIPTION : Execute the action of the SEND state						*/
/*		- Put received TPDU into FIFO since the Link layer is waiting for a	*/
/*		acknowlegde of the precedent sent LPDU								*/
/*		- On received acknowlegde, send a LPDU of another tcid : 			*/
/*		multiplexing on the same slot										*/
/*		- Receive LPDU from PHYSICAL task, assemble LPDU into complete		*/
/*		TPDU and send them to TRANS Task									*/
/* 									    									*/
/* INPUT PARAMETERS :							    						*/
/*		lnkSlotIndex :		instance of the current state diagram					*/
/*		evt :		current event (transition)								*/
/*		nExtraInfo :		conditionnal information according to the event			*/
/*			evt = TPDU / LN_ACK : nExtraInfo = index of g_lnk_tab_tcid				*/
/*			evt = LN_ERROR : 	  nExtraInfo = status of error					*/
/*									 										*/
/* RETURN CODE								    							*/
/*		1 : Success															*/
/*		0 : Error															*/
/*									  										*/
/* ======================================================================== */
int LINK_Send(int lnkSlotIndex, unsigned char evt, int nExtraInfo, xmsg_t* pXmsg)
{                                                                          
	int iRet;				/* return code  		*/
	int tcidIndex;			/* index of g_lnk_tab_tcid	*/
	int i;					/* working index		*/
	unsigned short slotId;	/* current slot 		*/
	int nb;					/* number of multiplexing try */
	xmsg_t		xmsg;

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_Send() - entry,lnkSlotIndex=%d,evt=%s(0x%02X),nExtraInfo=%d\r\n",
					lnkSlotIndex, XMSG_NAME(evt), evt, nExtraInfo);

	SM_TRACE_INFO(TRMOD_LINK,"LINK_Send() - after entry, lnkSlotIndex=%d curstate=%s(%d) "
					"evt=%s(0x%02X)\r\n", 
					lnkSlotIndex, 
					GETLINKSTATNAME(g_lnk_tab_slot[lnkSlotIndex].m_state), 
					g_lnk_tab_slot[lnkSlotIndex].m_state, 
					XMSG_NAME(evt),
					evt);

	switch(evt)
	{
	case LN_ACK:
		tcidIndex = nExtraInfo;			     
		g_lnk_tab_slot[lnkSlotIndex].m_isTpduSending = 0;		/* no more LN_ACK to receive on this slot */
			
		/* Perform multiplexing on the current slot 			*/            
		/* ========================================				*/
		/* Look for a tcid beginning by the tcid that follows 	*/
		/* the current one acknowledged .                       */
		/* A tcid is eligible if on this tcid  : 				*/
		/*		- a TPDU is being sent							*/
		/*		- a TPDU is in FIFO to be sent					*/  
			
		slotId = g_lnk_tab_slot[lnkSlotIndex].m_slotId;	           

		/* optimization if there is only one tcid on the current slot */
		/* ============												  */
		if (g_lnk_tab_slot[lnkSlotIndex].m_tcidCount == 1)
			i = tcidIndex;		/* take the same */
		else
		{				
			i = tcidIndex + 1;	/* beginning by the next tcid */				
			if (i == MAXTCID)
				i = 0;            
		}
			
		/* Perform the multiplexing on the current slot */
		/* ============================================ */
		nb = 0;
		do
		{                            
			if (g_lnk_tab_tcid[i].m_slotId == slotId)
			{
				/* Search on the current slot */
				if (g_lnk_tab_tcid[i].m_sendSize > 0)
				{	
					/* a TPDU is partially sent, take the next LPDU and */
					/* Send LPDU to PHYSICAL Task */
					/* ========================== */
					iRet = LINK_SendLPDU(lnkSlotIndex, i, g_lnk_tab_tcid[i].m_tcid, NULL, 0);
					break;		/* stop the loop : next eligible tcid found  */
				}					
				else
				{   /* Search into FIFO, if a TPDU exists, Send the first LPDU */
					/* take mn_msg1 since pXmsg->m_msg.m_body is for the received LN_ACK    */
					memset(&xmsg, 0x00, sizeof(xmsg));
					xmsg.m_type = TPDU;
					iRet = LINK_GetFifo(i, &(xmsg.m_bd.m_tpdu));
					if (iRet)
					{
						/* Send LPDU to PHYSICAL Task */
						/* ========================== */
						iRet = LINK_SendLPDU(lnkSlotIndex, i, g_lnk_tab_tcid[i].m_tcid, 
									xmsg.m_bd.m_tpdu.m_pbTpdu, xmsg.m_bd.m_tpdu.m_len);
						if (!iRet) //send LPDU failed
							FreeXmsg(&xmsg); //add by pmy
						break;	/* stop the loop : next eligible tcid found  */
					}
				}
			}	
			
			i++;	/* next tcid : multiplexing */
			nb++;
			if (i == MAXTCID)
				i = 0;
		}while (nb < MAXTCID);
			
		if (! g_lnk_tab_slot[lnkSlotIndex].m_isTpduSending)
		   	/* Set the new state */
			g_lnk_tab_slot[lnkSlotIndex].m_state = LN_STAT_CONNECTED;	/* no more LPDU to send on this slot and all LN_ACK received */
			
		break;  /* end of LN_ACK processing */
			
	case TPDU :			
		/* wait for an LN_ACK from a precedent LPDU sending */
		iRet = LINK_PutFifo(nExtraInfo, &(pXmsg->m_bd.m_tpdu));
		if (iRet)
		{
			/* Success : keep memory since the TPDU is not copied in FIFO, only the pointer */				
			pXmsg->m_bd.m_tpdu.m_pbTpdu = NULL;
		}

		break;	/* end of TPDU processing */

	case LPDU :						
	case LN_ERROR :						
	case LN_DISCONNECT :			                 
		/* same case that for the LN_STAT_CONNECTED state */
		iRet = LINK_Connected(lnkSlotIndex, evt, nExtraInfo, pXmsg);			
		break;	/* end of LPDU / LN_ERROR / LN_DISCONNECT processing */

	default :	/* protocol error, ignore the event */
		SM_TRACE_ERROR(TRMOD_LINK, "LINK_Send() - protocol error . event %d received in %d state\r\n", evt, g_lnk_tab_slot[lnkSlotIndex].m_state);
		iRet = 0;
		break;			
	}

	SM_TRACE_INFO(TRMOD_LINK,"LINK_Send() - before return, lnkSlotIndex=%d curstate=%s(%d) "
					"evt=%s(0x%02X)\r\n", 
					lnkSlotIndex, 
					GETLINKSTATNAME(g_lnk_tab_slot[lnkSlotIndex].m_state), 
					g_lnk_tab_slot[lnkSlotIndex].m_state, 
					XMSG_NAME(evt),
					evt);

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_Send() - return,iRet=%d\r\n", iRet);
	return iRet;
}	/* end of SEND state */
	

/* ======================================================================== */
/* NAME : LINK_SendLPDU							 							*/
/* 									    									*/
/* DESCRIPTION : Send a LPDU to the PHYSICAL Task							*/
/*									 										*/
/* INPUT PARAMETERS :							    						*/
/*		lnkSlotIndex :		 instance of the current state diagram / slot			*/
/*		tcidIndex : instance of the current tcid							*/
/*		lpdu :		 pointer to the LPDU to send							*/
/*					 or NULL if the pointer is already in g_lnk_tab_tcid		*/
/*		length :	 length of LPDU to send if lpdu != NULL					*/
/*									 										*/
/* OUTPUT PARAMETERS :							   							*/
/*	If the LPDU is the last (or the only one), free the memory containing	*/
/*	the complete TPDU														*/
/*	If the LPDU is not the last, update the g_lnk_tab_tcid entry with pointer	*/
/*	to the next LPDU to send 												*/
/*	g_lnk_tab_tcid[].tcid/send are updated										*/
/*									    									*/
/* RETURN CODE								    							*/
/*		1 : Success															*/
/*		0 : Error															*/
/*									  										*/
/* ======================================================================== */
int LINK_SendLPDU(int lnkSlotIndex, int tcidIndex, unsigned char tcid, 
				  unsigned char *lpdu, unsigned long length)
{    
	unsigned char*	ptr;		/* pointer to LPDU to send 							*/
	unsigned long	len;		/* length of LPDU to send							*/
	unsigned char	flag;		/* MORE / LAST flag									*/
	xmsg_t			xmsg;

	SM_TRACE_ENTRY(TRMOD_LINK, "LINK_SendLPDU() - entry,lnkSlotIndex=%d,tcidIndex=%d,tcid=%d,"
				"lpdu=0x%08X,length=%d\r\n", lnkSlotIndex, tcidIndex,tcid,lpdu,length);

	if (lpdu == NULL)	                                     
	{	/* pointer to LPDU already in g_lnk_tab_tcid */
		ptr  = g_lnk_tab_tcid[tcidIndex].m_pbSend;
		len = g_lnk_tab_tcid[tcidIndex].m_sendSize;
	}                                  
	else           
	{                              
		/* Initialize g_lnk_tab_tcid and save the TPDU pointer for further memory release */
        g_lnk_tab_tcid[tcidIndex].m_pbTpdu = lpdu;
        g_lnk_tab_tcid[tcidIndex].m_pbSend = lpdu;
        g_lnk_tab_tcid[tcidIndex].m_sendSize = length;

		ptr  = lpdu;
		len = length;
	}   

	/* Check if the LPDU's size is greater then the negociateg physical buffer size */	
	if ((len + 2) > g_lnk_tab_slot[lnkSlotIndex].m_negoSize)
	{	/* more than one LPDU */
		flag = LN_MORE;
		len = g_lnk_tab_slot[lnkSlotIndex].m_negoSize - 2;

		/* Update the g_lnk_tab_tcid entry for the next LPDU to send */
		g_lnk_tab_tcid[tcidIndex].m_pbSend = ptr + len;
		g_lnk_tab_tcid[tcidIndex].m_sendSize -= len;
	}
	else
	{
		/* only one LPDU */
		flag = LN_LAST;

		g_lnk_tab_tcid[tcidIndex].m_sendSize = 0;

	}

	/* send LPDU to the PHYSICAL Task */
	/* ============================== */
	//pmy when fastalloc	/* A fast small allocation is used since the allocation size is equal to the maximum negociated size added to the header message . length = len + 2 */
	memset(&xmsg, 0x00, sizeof(xmsg));
	xmsg.m_bd.m_lpdu.m_pbLpdu = ITC_DynAlloc((unsigned short)(len+2));	/* The allocation size is equal to the maximum negociated size added to the header message . length = len + 2 */
	if (xmsg.m_bd.m_lpdu.m_pbLpdu == NULL)
	{
		SM_TRACE_ERROR(TRMOD_LINK, "LINK_SendLPDU() - can't allocate buffer for coding TPDU\r\n");
		return 0;	/* Error */
	}

	xmsg.m_sndrcver	 = (LINK << 4) | PHYSICAL;
	xmsg.m_type      = LPDU;
	xmsg.m_bd.m_lpdu.m_slotId = g_lnk_tab_slot[lnkSlotIndex].m_slotId;
	xmsg.m_bd.m_lpdu.m_len	 = (unsigned short)len + 2;

	*(xmsg.m_bd.m_lpdu.m_pbLpdu)     = tcid;
	*(xmsg.m_bd.m_lpdu.m_pbLpdu + 1) = flag;
	memcpy(xmsg.m_bd.m_lpdu.m_pbLpdu + 2, ptr, len);		
	if (flag == LN_LAST)
	{
		/* free TPDU memory since the TPDU is already sent */
		ITC_DynFree(g_lnk_tab_tcid[tcidIndex].m_pbTpdu);
		g_lnk_tab_tcid[tcidIndex].m_pbTpdu = NULL;
	}

	SM_TRACE_BYTES(TRMOD_LINK, TRLEV_NOTIFY, 
					xmsg.m_bd.m_lpdu.m_pbLpdu, xmsg.m_bd.m_lpdu.m_len,
					"LINK_SendLPDU() - send data[slotId=%d]:", 
					xmsg.m_bd.m_lpdu.m_slotId);

	if (!ITC_SendXmsg(&xmsg))
	{
		SM_TRACE_ERROR(TRMOD_LINK, "LINK_SendLPDU() - Can't send the LPDU for %d slot to PHYSICAL Task\r\n", g_lnk_tab_slot[lnkSlotIndex].m_slotId);
		FreeXmsg(&xmsg);
		return 0;		/* Error */
	}

	g_lnk_tab_slot[lnkSlotIndex].m_tcid = tcid;		/* TPDU is sent on this tcid */
	g_lnk_tab_slot[lnkSlotIndex].m_isTpduSending = 1;		/* LPDU sending	in progress	 */

	SM_TRACE_RETURN(TRMOD_LINK, "LINK_SendLPDU() - return 1\r\n");
	return 1;			/* Success */
}
